package com.luhuiguo.cms.client.presenter;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.TreeItem;
import com.google.inject.Inject;
import com.luhuiguo.cms.client.AppConstants;
import com.luhuiguo.cms.client.AppMessages;
import com.luhuiguo.cms.shared.event.ChannelCreatedEvent;
import com.luhuiguo.cms.shared.event.ChannelUpdatedEvent;
import com.luhuiguo.cms.shared.event.EditChannelCancelledEvent;
import com.luhuiguo.cms.shared.event.FlashEvent;
import com.luhuiguo.cms.shared.model.ArticleModel;
import com.luhuiguo.cms.shared.model.ChannelModel;
import com.luhuiguo.cms.shared.rpc.CreateChannel;
import com.luhuiguo.cms.shared.rpc.CreateChannelResult;
import com.luhuiguo.cms.shared.rpc.UpdateChannel;
import com.luhuiguo.cms.shared.rpc.UpdateChannelResult;
import com.luhuiguo.gwt.dispatcher.client.DispatcherAsync;
import com.luhuiguo.gwt.presenter.client.EventBus;
import com.luhuiguo.gwt.presenter.client.widget.WidgetDisplay;
import com.luhuiguo.gwt.presenter.client.widget.WidgetPresenter;
import com.luhuiguo.gwt.validation.client.ValidationException;
import com.luhuiguo.gwt.validation.client.ValidationProcessor;

public class EditChannelPresenter extends WidgetPresenter<EditChannelPresenter.Display> {

    public interface Display extends WidgetDisplay {

        HasClickHandlers getSubmitButton();

        HasClickHandlers getCancelButton();

        HasValue<String> getNameField();

        HasValue<String> getTitleField();

        HasValue<String> getRankField();

        ValidationProcessor getValidator();

        boolean validate();

        void setLoading(boolean loading);

        void setNameEnabled(boolean enabled);

    }

    private DispatcherAsync dispatcher;

    private AppMessages messages;

    private AppConstants constants;

    private TreeItem treeItem;

    private ChannelModel channel;

    @Inject
    public EditChannelPresenter(Display display, EventBus eventBus, DispatcherAsync dispatcher, AppConstants constants,
            AppMessages messages) {
        super(display, eventBus);
        this.dispatcher = dispatcher;
        this.constants = constants;
        this.messages = messages;

        GWT.log("EditChannelPresenter created");

    }

    @Override
    protected void onBind() {
        GWT.log("EditChannelPresenter onBind");

        registerHandler(display.getSubmitButton().addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                if (display.validate()) {
                    if (null == channel.getId()) {
                        createChannel();
                    } else {
                        updateChannel();
                    }
                }

            }
        }));

        registerHandler(display.getCancelButton().addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                doReset();
                eventBus.fireEvent(new EditChannelCancelledEvent());
            }
        }));

    }

    @Override
    protected void onRevealDisplay() {
        GWT.log("EditChannelPresenter onRevealDisplay");

    }

    @Override
    protected void onUnbind() {
        GWT.log("EditChannelPresenter onUnbind");

    }

    private void createChannel() {
        display.setLoading(true);

        updateModel(channel);

        dispatcher.execute(new CreateChannel(channel), new AsyncCallback<CreateChannelResult>() {

            @Override
            public void onFailure(Throwable caught) {
                display.setLoading(false);
                if (caught instanceof ValidationException) {
                    display.getValidator().processServerErrors((ValidationException) caught);
                } else {
                    eventBus.fireEvent(new FlashEvent(messages.saveChannelFailed(channel.getTitle()), -1));
                }
            }

            @Override
            public void onSuccess(CreateChannelResult result) {
                display.setLoading(false);
                eventBus.fireEvent(new ChannelCreatedEvent(result.get(), treeItem));
                doReset();

            }
        });

    }

    private void updateChannel() {
        display.setLoading(true);

        updateModel(channel);

        dispatcher.execute(new UpdateChannel(channel), new AsyncCallback<UpdateChannelResult>() {

            @Override
            public void onFailure(Throwable caught) {
                display.setLoading(false);
                if (caught instanceof ValidationException) {
                    display.getValidator().processServerErrors((ValidationException) caught);
                } else {
                    eventBus.fireEvent(new FlashEvent(messages.saveChannelFailed(channel.getTitle()), -1));
                }
            }

            @Override
            public void onSuccess(UpdateChannelResult result) {
                display.setLoading(false);
                eventBus.fireEvent(new ChannelUpdatedEvent(result.getNew(), treeItem));
                doReset();

            }
        });

    }

    protected void loadModel(ChannelModel channel) {
        display.getNameField().setValue(channel.getName());
        display.getTitleField().setValue(channel.getTitle());
        display.getRankField().setValue(Integer.toString(channel.getRank()));
    }

    protected void updateModel(ChannelModel channel) {
        channel.setName(display.getNameField().getValue());
        channel.setTitle(display.getTitleField().getValue());
        channel.setRank(Integer.parseInt(display.getRankField().getValue()));
    }

    private void doReset() {
        display.getNameField().setValue("");
        display.getTitleField().setValue("");
        display.getRankField().setValue("");
        display.getValidator().reset();
    }

    public void revealDisplay(TreeItem treeItem, ChannelModel channel) {

        this.treeItem = treeItem;
        this.channel = channel;

        if (null == channel.getId()) {
            display.setNameEnabled(true);
        } else {
            display.setNameEnabled(false);
        }
        loadModel(channel);
        revealDisplay();
    }

}
